using System;
using System.Diagnostics;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using DE.Sdc.SharePoint.SPContentStructure.Common;

namespace DE.Sdc.SharePoint.SPContentStructure.Import
{
    [Serializable]
    [XmlType(AnonymousType = true, Namespace = DeploymentConstants.Namespace)]
    [XmlRoot(Namespace = DeploymentConstants.Namespace, IsNullable = false)]
    public class ContentType : HierarchicalElement<List>, IImportDefinition<SPContentType, SPList>
    {
        /// <remarks/>
        [XmlAttribute]
        public QualifierType IdQualifier { get; set; }

        [XmlIgnore]
        public SPContentType UpdatedSPObject { get; internal set; }

        public void ImportDefinition(SPContentType contentType, SPList parentList)
        {


            if (contentType != null &&
                (Action == ActionType.Delete ||
                 Action == ActionType.Replace))
                parentList.ContentTypes.Delete(contentType.Id);

            if (Action == ActionType.AddOrUpdate ||
                Action == ActionType.Replace)
            {
                if (contentType == null)
                    throw new ArgumentOutOfRangeException(
                        String.Format("ContentType with {0} '{1}' could not be found",
                                      IdQualifier, Id));

                var bestMatchContentType = parentList.ContentTypes.BestMatch(contentType.Id);

                if (parentList.ContentTypes[contentType.Name] == null &&
                    !bestMatchContentType.IsChildOf(contentType.Id))
                {
                    try
                    {
                        parentList.ContentTypes.Add(contentType);
                    }
                    catch (Exception ex)
                    {
                        throw new ContentStructureException(
                            string.Format("Error while adding contenttype '{0}'", contentType.Name), ex);
                    }
                }
            }

            if (contentType != null && Action != ActionType.None &&
                Action <= ActionType.AddOrUpdateOrReplace &&
                parentList.ContentTypes[contentType.Name] == null &&
                parentList.ContentTypes[contentType.Id] == null)
            {
                for (int fieldIndex = 0; fieldIndex < contentType.Fields.Count; fieldIndex++)
                {
                    SPField contentTypeField = contentType.Fields[fieldIndex];
                    SPField listField;
                    SPFieldCollection fieldCollection = parentList.Fields;

                    if (parentList.Fields.ContainsField(contentTypeField.InternalName))
                    {
                        try
                        {
                            listField = parentList.Fields.GetField(contentTypeField.InternalName);
                        }
                        catch (Exception)
                        {
                            // Workaround, sometimes you have to call the line twice before it works (SharePoint bug).
                            listField = parentList.Fields.GetField(contentTypeField.InternalName);
                        }
                        if ((contentTypeField.Type != listField.Type) && (!(listField is SPFieldLookup)))
                        {
                            listField.Type = contentTypeField.Type;
                            listField.Update(true);
                        }
                    }
                    else
                    {

                        string fieldname;
                        if (contentTypeField is SPFieldLookup)
                        {
                            Guid lookupWebId;
                            try
                            {
                                lookupWebId = ((SPFieldLookup) contentTypeField).LookupWebId;
                            }
                            catch (FormatException)
                            {
                                lookupWebId = parentList.ParentWeb.Site.RootWeb.ID;
                            }
                            Guid lookupListId;
                            try
                            {
                                lookupListId = new Guid(((SPFieldLookup) contentTypeField).LookupList);
                            }
                            catch (FormatException)
                            {
                                using (var lookupWeb = parentList.ParentWeb.Site.OpenWeb(lookupWebId))
                                {
                                    lookupListId =
                                        lookupWeb.Lists[((SPFieldLookup) contentTypeField).LookupList].ID;
                                }
                            }
                            Guid lookupFieldId;
                            try
                            {
                                lookupFieldId = new Guid(((SPFieldLookup) contentTypeField).LookupField);
                            }
                            catch (FormatException)
                            {
                                using (var lookupWeb = parentList.ParentWeb.Site.OpenWeb(lookupWebId))
                                {
                                    lookupFieldId =
                                        lookupWeb.Lists[lookupListId].Fields.GetFieldByInternalName(
                                            ((SPFieldLookup) contentTypeField).LookupField).Id;
                                }
                            }
                            fieldname = fieldCollection.AddLookup(contentTypeField.InternalName, lookupListId,
                                                                  lookupWebId, contentTypeField.Required);
                        }
                        else
                        {
                            fieldname = fieldCollection.Add(contentTypeField.InternalName, contentTypeField.Type,
                                                            contentTypeField.Required);
                        }
                        parentList.Update();

                        SPField field = fieldCollection.GetField(fieldname);
                        try
                        {
                            field.Title = contentTypeField.Title;
                            field.Hidden = contentTypeField.Hidden;
                            field.Indexed = contentTypeField.Indexed;
                            field.ReadOnlyField = contentTypeField.ReadOnlyField;
                            if (!(field is SPFieldLookup))
                                field.Type = contentTypeField.Type;
                        }
                        catch (Exception e)
                        {
                            Trace.WriteLine("Exception in ModifyContentTypes (SPField): " + e.Message);
                        }
                        if (field is SPFieldLookup)
                        {
                            try
                            {
                                ((SPFieldLookup) field).LookupField =
                                    ((SPFieldLookup) contentTypeField).LookupField;
                                ((SPFieldLookup) field).AllowMultipleValues =
                                    ((SPFieldLookup) contentTypeField).AllowMultipleValues;
#if !SP_07
                                    ((SPFieldLookup) field).IsRelationship =
                                    ((SPFieldLookup) contentTypeField).IsRelationship;
#endif

                                try
                                {
                                    ((SPFieldLookup) field).PrependId =
                                        ((SPFieldLookup) contentTypeField).PrependId;
                                }
                                catch
                                {
                                }
#if !SP_07
                                 try
                                {
                                    ((SPFieldLookup) field).PrimaryFieldId =
                                        ((SPFieldLookup) contentTypeField).PrimaryFieldId;
                                }
                                catch
                                {
                                }
                                try
                                {
                                    ((SPFieldLookup) field).RelationshipDeleteBehavior =
                                        ((SPFieldLookup) contentTypeField).RelationshipDeleteBehavior;
                                }
                                catch
                                {
                                }
#endif

                            }
                            catch (Exception exception)
                            {
                                Trace.WriteLine(
                                    "ModifyContentTypes: Exception while deployment of SPFieldLookup: " +
                                    exception.Message);
                            }
                        }

                        field.Update();

                        //fieldCollection.AddFieldAsXml(contentTypeField.SchemaXml, true, SPAddFieldOptions.Default);
                        parentList.Update();
                    }
                }
            }

            UpdatedSPObject = contentType;
        }

    }
}